ig.module('game.entities.player').requires('impact.entity', 'game.entities.particle').defines(function () {
    EntityPlayer = ig.Entity.extend({
        size: {
            x: 8,
            y: 14
        },
        offset: {
            x: 4,
            y: 2
        },
        maxVel: {
            x: 120,
            y: 240
        },
        accelDef: {
            ground: 400,
            air: 200
        },
        frictionDef: {
            ground: 400,
            air: 100
        },
        jump: 120,        
        bounciness: 0,
        health: 1000,
        type: ig.Entity.TYPE.A,
        checkAgainst: ig.Entity.TYPE.NONE,
        collides: ig.Entity.COLLIDES.PASSIVE,
        flip: false,
        flippedAnimOffset: 24,
        idle: false,
        moved: false,
        standing: false,
        canHighJump: false,
        highJumpTimer: null,
        idleTimer: null,
        sfxPlasma: new ig.Sound('media/sounds/plasma.ogg'),
        sfxDie: new ig.Sound('media/sounds/die-respawn.ogg', false),
        animSheet: new ig.AnimationSheet('media/sprites/player.png', 16, 16),
        inputSource: null,
        init: function (x, y, settings) {
            this.inputSource = ig.input;
            this.friction.y = 0;
            this.parent(x, y, settings);
            this.idleTimer = new ig.Timer();
            this.highJumpTimer = new ig.Timer();
            this.addAnim('idle', 1, [0]);
            this.addAnim('scratch', 0.3, [2, 1, 2, 1, 2], true);
            this.addAnim('shrug', 0.3, [3, 3, 3, 3, 3, 3, 4, 3, 3], true);
            this.addAnim('run', 0.07, [6, 7, 8, 9, 10, 11]);
            this.addAnim('jump', 1, [15]);
            this.addAnim('fall', 0.4, [12, 13]);
            this.addAnim('land', 0.15, [14]);
            this.addAnim('die', 0.07, [18, 19, 20, 21, 22, 23, 16, 16, 16]);
            this.addAnim('spawn', 0.07, [16, 16, 16, 23, 22, 21, 20, 19, 18]);
        },
        update: function () {
            if (this.currentAnim == this.anims.spawn) {
                this.currentAnim.update();
                if (this.currentAnim.loopCount) {
                    this.currentAnim = this.anims.idle.rewind();
                } else {
                    return;
                }
            }
            if (this.currentAnim == this.anims.die) {
                this.currentAnim.update();
                if (this.currentAnim.loopCount) {
                    this.kill();
                }
                return;
            }
            this.moved = false;
            this.wasStanding = this.standing;
            this.friction.x = this.standing ? this.frictionDef.ground : this.frictionDef.air;
            if (this.inputSource.state('left')) {
                
                this.accel.x = -(this.standing ? this.accelDef.ground : this.accelDef.air);
                this.flip = true;
                this.moved = true;
            } else if (this.inputSource.state('right')) {
                
                this.accel.x = (this.standing ? this.accelDef.ground : this.accelDef.air);
                this.flip = false;
                this.moved = true;
            } else {
                this.accel.x = 0;
            }
            if (this.inputSource.pressed('shoot')) {
                
                var x = this.pos.x + (this.flip ? -3 : 5);
                var y = this.pos.y + 6;
                ig.game.spawnEntity(EntityProjectile, x, y, {
                    flip: this.flip
                });
                this.sfxPlasma.play();
            }
            if (this.standing && (this.inputSource.pressed('jump') || (!this.wasStanding && this.inputSource.pressed('jump')))) {
                this.canHighJump = 1;
                this.highJumpTimer.set(0.14);
                this.vel.y = -this.jump / 4;
            } else if (this.canHighJump) {
                var d = this.highJumpTimer.delta();
                if (this.inputSource.state('jump')) {
                    var f = Math.max(0, d > 0 ? ig.system.tick - d : ig.system.tick);
                    this.vel.y -= this.jump * f * 6.5;
                } else {
                    this.canHighJump = false;
                }
                if (d > 0) {
                    this.canHighJump = false;
                }
            }
            this.parent();
            this.setAnimation();
        },
        setAnimation: function () {
            if ((!this.wasStanding && this.standing)) {
                this.currentAnim = this.anims.land.rewind();
            } else if (this.standing && (this.currentAnim != this.anims.land || this.currentAnim.loopCount > 0)) {
                if (this.moved) {
                    if (this.standing) {
                        this.currentAnim = this.anims.run;
                    }
                    this.idle = false;
                } else {
                    if (!this.idle || this.currentAnim.stop && this.currentAnim.loopCount > 0) {
                        this.idle = true;
                        this.idleTimer.set(Math.random() * 4 + 3);
                        this.currentAnim = this.anims.idle;
                    }
                    if (this.idleTimer.delta() > 0) {
                        this.idleTimer.reset();
                        this.currentAnim = [this.anims.scratch, this.anims.shrug].random().rewind();
                    }
                }
            } else if (!this.standing) {
                if (this.vel.y < 0) {
                    this.currentAnim = this.anims.jump;
                } else {
                    if (this.currentAnim != this.anims.fall) {
                        this.anims.fall.rewind();
                    }
                    this.currentAnim = this.anims.fall;
                }
                this.idle = false;
            }
            this.currentAnim.flip.x = this.flip;
            if (this.flip) {
                this.currentAnim.tile += this.flippedAnimOffset;
            }
        },
        collideWith: function (other, axis) {
            if (axis == 'y' && this.standing && this.currentAnim != this.anims.die) {
                this.currentAnim.update();
                this.setAnimation();
            }
        },
        receiveDamage: function (amount, from) {
            if (this.currentAnim != this.anims.die) {                
                this.currentAnim = this.anims.die.rewind();
                for (var i = 0; i < 3; i++) {
                    ig.game.spawnEntity(EntityPlayerGib, this.pos.x, this.pos.y);
                }
                ig.game.spawnEntity(EntityPlayerGibGun, this.pos.x, this.pos.y);
                this.sfxDie.play();
            }
        },
        kill: function () {
            this.parent();
            ig.game.respawnPlayerAtLastCheckpoint(this.pos.x, this.pos.y);
        }
    });
    EntityPlayerGib = EntityParticle.extend({
        lifetime: 0.8,
        fadetime: 0.4,
        friction: {
            x: 0,
            y: 0
        },
        vel: {
            x: 30,
            y: 80
        },
        gravityFactor: 0,
        animSheet: new ig.AnimationSheet('media/sprites/player.png', 8, 8),
        init: function (x, y, settings) {
            this.addAnim('idle', 7, [82, 94]);
            this.parent(x, y, settings);
        }
    });
    EntityPlayerGibGun = EntityParticle.extend({
        lifetime: 2,
        fadetime: 0.4,
        size: {
            x: 8,
            y: 8
        },
        friction: {
            x: 30,
            y: 0
        },
        vel: {
            x: 60,
            y: 50
        },
        animSheet: new ig.AnimationSheet('media/sprites/player.png', 8, 8),
        init: function (x, y, settings) {
            this.addAnim('idle', 0.5, [11]);
            this.parent(x, y, settings);
            this.currentAnim.flip.y = false;
        }
    });
    
    EntityProjectile = ig.Entity.extend({
        size: {
            x: 6,
            y: 3
        },
        offset: {
            x: 1,
            y: 2
        },
        maxVel: {
            x: 200,
            y: 0
        },
        gravityFactor: 0,
        type: ig.Entity.TYPE.NONE,
        checkAgainst: ig.Entity.TYPE.B,
        collides: ig.Entity.COLLIDES.NEVER,
        flip: false,
        hasHit: false,
        animSheet: new ig.AnimationSheet('media/sprites/projectile.png', 8, 8),
        init: function (x, y, settings) {
            this.parent(x, y, settings);
            this.vel.x = (settings.flip ? -this.maxVel.x : this.maxVel.x);
            this.addAnim('idle', 1, [0]);
            this.addAnim('hit', 0.1, [0, 1, 2, 3, 4, 5], true);
        },
        update: function () {
            if (this.hasHit && this.currentAnim.loopCount > 0) {
                this.kill();
            }
            this.parent();
            this.currentAnim.flip.x = this.flip;
        },
        handleMovementTrace: function (res) {
            this.parent(res);
            if (res.collision.x || res.collision.y) {
                this.currentAnim = this.anims.hit;
                this.hasHit = true;
            }
        },
        check: function (other) {            
            if (!this.hasHit) {
                other.receiveDamage(10, this);
                this.hasHit = true;
                this.currentAnim = this.anims.hit;
                this.vel.x = 0;
            }
        }
    });
});
